package ce.com.cenewbluesdk.bluetooth;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Handler;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import ce.com.cenewbluesdk.CEBC;
import ce.com.cenewbluesdk.uitl.Lg;

/**
 * Created by Administrator on 2016/11/9 0009.
 */
public class CEBlueTooth_4 extends CEBlueToothBase {
    private BluetoothGatt mBluetoothGatt;
    private BluetoothAdapter adapter;
    private Context mContext;
    private String mBluetoothDeviceAddress = "";
    private BluetoothDevice mBluetoothDevice = null;
    public int curWriteCharasIndex = 1;
    private byte[] currentBtyes;
    private boolean mConnected = false;

    private String Uuid;


    private List<BluetoothGattService> mBluetoothGattServices = null;
    private List<BluetoothGattCharacteristic> writeCharas = new ArrayList<BluetoothGattCharacteristic>();
    private List<BluetoothGattCharacteristic> readCharas = new ArrayList<BluetoothGattCharacteristic>();


    private Handler handler=new Handler();
    private FaidRun faidRun=new FaidRun();
    private class FaidRun implements Runnable{
        @Override
        public void run() {
            Lg.e("Ce blue_4","发现服务超时");
            internalDisConnect();
            blueToothConnectStateChange(CEBC.BLUE_DISCONNECT);
        }
    }




    private void startHandler(){
        handler.removeCallbacks(faidRun);
        handler.postDelayed(faidRun,8*1000);
    }
    private void clearHandler(){
        handler.removeCallbacks(faidRun);
    }


    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

            if (gatt != mBluetoothGatt) {
                String logStr = String.format("%s != %s", gatt == null ? "null" : gatt.getDevice(), mBluetoothGatt == null ? "null" : mBluetoothGatt.getDevice());
                Lg.e(logStr);
                return;
            }

            try {
                Lg.e("onConnectionStateChange： newState = " + newState);
                if (newState == BluetoothProfile.STATE_CONNECTED) {
                    mConnected = true;

                    // in our case we would also like automatically to call for services discovery
                    startServicesDiscovery();

                    // and we also want to get RSSI value to be updated periodically
                    //startMonitoringRssiValue();
                } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                    blueToothConnectStateChange(CEBC.BLUE_DISCONNECT);
                    mConnected = false;
//                    mUiCallback.uiDeviceDisconnected(mBluetoothGatt, mBluetoothDevice);
                } else {
                    mConnected = false;
                }
            } catch (Exception e) {

                e.printStackTrace();
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);

            Lg.e("blue_4","status="+status);

            if (status == BluetoothGatt.GATT_SUCCESS) {
                // now, when services discovery is finished, we can call getServices() for Gatt

                getSupportedServices();
                processOldRWCharacteristic(mBluetoothGattServices);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
            // we got response regarding our request to fetch characteristic value
            if (status == BluetoothGatt.GATT_SUCCESS) {
                // and it success, so we can get the value
                getCharacteristicValue(characteristic);
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                dataSendSucceed(currentBtyes);
            } else {
                dataSendFailed(currentBtyes);
            }

        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            getCharacteristicValue(characteristic);
//            if (currentBtyes != null) {
//                blueToothReceiptDate(currentBtyes);
//            }
        }
    };

    public CEBlueTooth_4(Context mContext, String UUID) {
        this.Uuid = UUID;
        this.mContext = mContext;
        BluetoothManager mBluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE);
        adapter = mBluetoothManager.getAdapter();
    }

    @Override
    public void connect(String mac) {
        if (mBluetoothDeviceAddress != null
                && mBluetoothDeviceAddress.equals(mac)
                && (blueConnectState == CEBC.BLUE_CONNECTING || blueConnectState == CEBC.BLUE_CONNECTED)) {
            Lg.e("本次连接将不会执行，当前连接状态："+blueConnectState+
                    "  连接的地址mDevice 地址 ："+mBluetoothDeviceAddress +"  mac:"+mac);
            return;

        }

        internalDisConnect();
        Log.e("liu", "开始连接");
        if (adapter == null || mac == null)
            return;


        mBluetoothDeviceAddress = mac;


        blueToothConnectStateChange(CEBC.BLUE_CONNECTING);
        // check if we need to connect from scratch or just reconnect to previous device
        if (mBluetoothGatt != null && mBluetoothGatt.getDevice().getAddress().equals(mac)) {
            // just reconnect
           if( !mBluetoothGatt.connect()){
               Lg.e("mBluetoothGatt.connect() is false");
               blueToothConnectStateChange(CEBC.BLUE_DISCONNECT);
           }
        } else {
            // connect from scratch
            // get BluetoothDevice object for specified address
            mBluetoothDevice = adapter.getRemoteDevice(mBluetoothDeviceAddress);
            if (mBluetoothDevice == null) {
                // we got wrong address - that device is not available!
                blueToothConnectStateChange(CEBC.BLUE_DISCONNECT);
                Lg.e(" mBluetoothDevice is null ");
                return;
            }
            // connect with remote device
            mBluetoothGatt = mBluetoothDevice.connectGatt(mContext, false, mGattCallback);
        }

    }

    @Override
    public void disConnect() {
        Log.e("liu", "断开连接");
        if (adapter == null || mBluetoothGatt == null) {
            return;
        }
        mBluetoothDeviceAddress = null;
        mBluetoothGatt.disconnect();
        close();
        blueToothConnectStateChange(CEBC.BLUE_DISCONNECT);

    }


    public void internalDisConnect() {
        Log.e("liu", "断开连接");
        if (adapter == null || mBluetoothGatt == null) {
            return;
        }
        mBluetoothDeviceAddress = null;
        mBluetoothGatt.disconnect();
        close();

    }


    @Override
    public void sendData(byte[] bytes) {
        curWriteCharasIndex++;
        if (curWriteCharasIndex >= writeCharas.size() - 1) {
            curWriteCharasIndex = 0;
        }

        sendData(curWriteCharasIndex, bytes);

    }

    @Override
    public void sendData(int index, byte[] bytes) {


        if (!mConnected) {
            dataSendFailed(bytes);
            return;
        }

        if (index < 0 || index >= writeCharas.size()) {
//            logd("写特征字序号不在范围内:" + charaIndex);

            sendData(bytes);
        } else {
            BluetoothGattCharacteristic chara = writeCharas.get(index);
            if (!chara.setValue(bytes)) {
//                logd("chara.setValue(data) return false");
            }
            currentBtyes = bytes;

            Lg.e("发送的数据：" + CEBC.byte2hex(currentBtyes));
            writeDataToCharacteristic(chara, bytes);
        }
    }

    /* request to discover all services available on the remote devices
        * results are delivered through callback object */

    public void close() {
        Log.d("liu", "close(), mBluetoothGatt = " + mBluetoothGatt);
        if (mBluetoothGatt != null) mBluetoothGatt.close();
        mBluetoothGatt = null;
//    	mBluetoothDevice = null;
    }

    public void startServicesDiscovery() {
        Lg.e("liu","开始发现服务");
        if (mBluetoothGatt != null){
            startHandler();
            mBluetoothGatt.discoverServices();
        }else{
            internalDisConnect();
            blueToothConnectStateChange(CEBC.BLUE_DISCONNECT);
        }

    }

    /* gets services and calls UI callback to handle them
     * before calling getServices() make sure service discovery is finished! */
    public void getSupportedServices() {
        if (mBluetoothGattServices != null && mBluetoothGattServices.size() > 0)
            mBluetoothGattServices.clear();
        // keep reference to all services in local array:
        if (mBluetoothGatt != null) mBluetoothGattServices = mBluetoothGatt.getServices();

    }

    /* get characteristic's value (and parse it for some types of characteristics)
     * before calling this You should always update the value by calling requestCharacteristicValue() */
    public void getCharacteristicValue(BluetoothGattCharacteristic ch) {
        if (adapter == null || mBluetoothGatt == null || ch == null) return;

        byte[] rawValue = ch.getValue();


        // lets read and do real parsing of some characteristic to get meaningful value from it
        java.util.UUID uuid = ch.getUuid();

        Lg.e("接收到的设备侧的数据：" + CEBC.byte2hex(rawValue));
        blueToothReceiptDate(rawValue);

    }

    /* set new value for particular characteristic */
    public void writeDataToCharacteristic(final BluetoothGattCharacteristic ch, final byte[] dataToWrite) {
        if (adapter == null || mBluetoothGatt == null || ch == null) return;

        // first set it locally....
        ch.setValue(dataToWrite);
        // ... and then "commit" changes to the peripheral
        mBluetoothGatt.writeCharacteristic(ch);
    }

    /* enables/disables notification for characteristic */
    public void setNotificationForCharacteristic(BluetoothGattCharacteristic ch, boolean enabled) {
        if (adapter == null || mBluetoothGatt == null) return;

        boolean success = mBluetoothGatt.setCharacteristicNotification(ch, enabled);
        if (!success) {
            Log.e("------", "Seting proper notification status for characteristic failed!");
        }
        // This is also sometimes required (e.g. for heart rate monitors) to enable notifications/indications
        // see: https://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
        BluetoothGattDescriptor descriptor = ch.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
        if (descriptor != null) {
            byte[] val = enabled ? BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE : BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
            descriptor.setValue(val);
            mBluetoothGatt.writeDescriptor(descriptor);
        }
    }

    private void processOldRWCharacteristic(List<BluetoothGattService> gattServices) {
        writeCharas.clear();
        if (gattServices == null) {
            return;
        }
        for (BluetoothGattService gattService : gattServices) {
            // 判断当前服务的UUID是否和预定的服务的UUID相等
            if (gattService
                    .getUuid()
                    .toString()
                    .toUpperCase()
                    .equals(UUID.fromString(Uuid).toString().toUpperCase())) {
                List<BluetoothGattCharacteristic> gattCharacteristics = gattService
                        .getCharacteristics();
                // 获取到写的特征
                for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                    final int charaProp = gattCharacteristic.getProperties();
                    Lg.e("charaProp = " +charaProp);
                    if (charaProp == 16) {
                        setNotificationForCharacteristic(
                                gattCharacteristic, true);
                        readCharas.add(gattCharacteristic);
                        Lg.e("发现的读特特征：" + gattCharacteristic.getUuid().toString());
                    } else {
                        if (!writeCharas.contains(gattCharacteristic)) {
                            writeCharas.add(gattCharacteristic);
                            Lg.e("发现的写特征：" + gattCharacteristic.getUuid().toString());
                        }

                    }
                }
                clearHandler();
                blueToothConnectStateChange(CEBC.BLUE_CONNECTED);
            }
        }
    }





}
